package xyz.riceball.usercore.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import xyz.riceball.develop.common.enums.ENRouteCheckType;
import xyz.riceball.framework.core.bean.ApiR;
import xyz.riceball.framework.core.bean.ApiRc;
import xyz.riceball.framework.core.context.UserContext;
import xyz.riceball.framework.core.enums.ENBool;
import xyz.riceball.framework.core.exception.RiceBallBizErrorException;
import xyz.riceball.framework.core.exception.RiceBallBizWarnException;
import xyz.riceball.framework.core.util.BeanUtils;
import xyz.riceball.framework.core.util.MessageUtils;
import xyz.riceball.framework.core.util.TransactionUtils;
import xyz.riceball.usercore.entity.dto.RouteDTO;
import xyz.riceball.usercore.entity.po.MenuRoutePO;
import xyz.riceball.usercore.entity.po.RoleRightPO;
import xyz.riceball.usercore.entity.po.RoutePO;
import xyz.riceball.usercore.mapper.MenuRouteMapper;
import xyz.riceball.usercore.mapper.RoleRightMapper;
import xyz.riceball.usercore.mapper.RouteMapper;
import xyz.riceball.usercore.service.RouteService;
import xyz.riceball.usercore.utils.TreeUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 路由表(Route)表服务实现类
 *
 * @author xiaovcloud
 * @since 2022-04-24 20:17:50
 */
@Slf4j
@Service("routeService")
public class RouteServiceImpl extends ServiceImpl<RouteMapper, RoutePO> implements RouteService {

    @Lazy
    @Resource
    private RequestMappingHandlerMapping handlerMapping;

    //    @Resource
//    private RouteLinkMapper routeLinkMapper;
    @Resource
    private RoleRightMapper roleRightMapper;
    @Resource
    private MenuRouteMapper menuRouteMapper;

    /**
     * 查询出免登录的接口
     *
     * @return
     */
    @Override
    public List<RoutePO> selectByNoLogin(int methodType) {
        QueryWrapper<RoutePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(RoutePO::getStatus, ENBool.TRUE.getValue())
                .eq(RoutePO::getOnline, ENBool.TRUE.getValue())
                .eq(RoutePO::getCheckType, ENRouteCheckType.NO_LOGIN.getValue())
                .eq(RoutePO::getMethodType,methodType);
        return list(queryWrapper);

    }

    /**
     * 查询出需登录的接口
     *
     * @return
     */
    @Override
    public List<RoutePO> selectByLogin(int methodType) {
        QueryWrapper<RoutePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(RoutePO::getStatus, ENBool.TRUE.getValue())
                .eq(RoutePO::getMethodType,methodType)
                .eq(RoutePO::getCheckType, ENRouteCheckType.LOGIN.getValue());
        return list(queryWrapper);
    }

    /**
     * 根据ID集合和请求方法查询出需授权的接口
     *
     * @param ids
     * @return
     */
    @Override
    public List<RoutePO> selectByIdsAndRequestMethod(List<String> ids) {
        QueryWrapper<RoutePO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(RoutePO::getId, ids).eq(RoutePO::getStatus, true)
//                .and(startDate -> startDate.le(RoutePO ::getStartDate, LocalDateTime.now()).or().isNull(routePO::getStartDate))
//                .and(endDate -> endDate.ge(RoutePO::getEndDate, LocalDateTime.now()).or().isNull(routePO::getEndDate))
                .eq(RoutePO::getCheckType, ENRouteCheckType.AUTH);
        return list(queryWrapper);
    }


//    /**
//     * 查询用户拥有的接口
//     *
//     * @param userId
//     * @return
//     */
//    @Override
//    public Map<String, RoutePO> selectRouteByUserId(String userId) {
//        List<RoutePO> routePOList = baseMapper.selectRouteByUserId(userId);
//        Map<String, RoutePO> map = new HashMap<>();
//        for (RoutePO routePO : routePOList) {
//            map.put(routePO.getHandlerMethodHash(), routePO);
//        }
//        return map;
//    }

    @Override
    public boolean refresh() {
        List<RoutePO> routeList = new ArrayList<>();
        // 拿到Handler适配器中的全部方法
//        Map<RequestMappingInfo, HandlerMethod> methodMap = handlerMapping.getHandlerMethods();
//        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : methodMap.entrySet()) {
//            RequestMappingInfo requestMappingInfo = entry.getKey();
//            HandlerMethod handlerMethod = entry.getValue();
//            Set<RequestMethod> requestMethodSet = requestMappingInfo.getMethodsCondition().getMethods();
//            Set<String> patterns = new HashSet<>();
//            if (entry.getKey().getPatternsCondition() != null) {
//                patterns = entry.getKey().getPatternsCondition().getPatterns();
//            }
//            if (requestMethodSet.size() > 0) {
//                for (RequestMethod requestMethod : requestMethodSet) {
//                    for (String pattern : patterns) {
//                        RoutePO routePO = new RoutePO();
////                        ApiOperation apiOperation = requestMethod.getDeclaringClass().getAnnotation(ApiOperation.class);
////                        if (apiOperation!=null) {
////                            routePO.setName(apiOperation.value());
////                        }
//                        routePO.setHandlerMethod(handlerMethod.toString());
//                        routePO.setHandlerMethodHash(DigestUtils.md5DigestAsHex(handlerMethod.toString().getBytes(StandardCharsets.UTF_8)));
//                        routePO.setRequestMethod(requestMethod.name());
//                        routePO.setPattern(pattern);
//                        routePO.setCheckType(RouteCheckType.LOGIN.getValue());
//                        routeList.add(routePO);
//                    }
//                }
//            } else {
//                for (String pattern : patterns) {
//                    RoutePO routePO = new RoutePO();
//                    routePO.setRequestMethod("*");
//                    routePO.setHandlerMethod(handlerMethod.toString());
//                    routePO.setHandlerMethodHash(DigestUtils.md5DigestAsHex(handlerMethod.toString().getBytes(StandardCharsets.UTF_8)));
//                    routePO.setPattern(pattern);
//                    routeList.add(routePO);
//                }
//            }
//        }
//        return updateOrSaveRoutePO(routeList);
        return true;
    }

//    /**
//     * 修改刷新route
//     *
//     * @param routeList controller扫描出来的路由
//     * @return
//     */
//    private boolean updateOrSaveRoutePO(List<RoutePO> routeList) {
//        //需要忽略的路径 swagger and error
//        List<String> ignoreUrl = List.of("/v2/api-docs", "/v3/api-docs", "/swagger-resources/configuration/ui",
//                "/swagger-resources", "/swagger-resources/configuration/security", "/error");
//        List<RoutePO> routeListTmp = routeList.stream().filter(o -> !ignoreUrl.contains(o.getPattern())).collect(Collectors.toList());
//
//        Map<String, List<RoutePO>> routeMap = routeListTmp.stream().collect(Collectors.groupingBy(o -> {
//            return o.getPattern() + o.getRequestMethod();
//        }));
//
//        //数据库查询出所有的路由
//        List<RoutePO> routeDbList = baseMapper.selectList(null);
//        for (RoutePO routeDb : routeDbList) {
//            String key = routeDb.getPattern() + routeDb.getHandlerMethod();
//            if (routeMap.containsKey(key)) {
//                //数据库已经存在条件
//                routeListTmp.removeAll(routeMap.get(key));
//            } else {
//                //数据库存在 没有扫描到的路由，需要删除
//                this.baseMapper.deleteById(routeDb);
//            }
//        }
//        //剩下的就是数据库没有的，直接新增就好
//        for (RoutePO route : routeListTmp) {
//            route.setOnline(ENBool.TRUE.getValue());
//            route.setOnOff(ENBool.TRUE.getValue());
//            this.baseMapper.insert(route);
//        }
//        return true;
//    }

    @Override
    public List<Tree<String>> tree() {
        List<Map<String, String>> map = getBaseMapper().tree();
        return TreeUtils.buildRoute(map);
    }

    @Override
    public List<RoutePO> selectRouteByRolesAndMethodType(List<String> roleList, int methodType) {
        return this.getBaseMapper().selectRouteByRolesAndMethodType(roleList, methodType);
    }

    @Override
    public ApiR<RouteDTO> add(RouteDTO routeDTO) {
        checkRouteBeforeDb(routeDTO);
        BeanUtils.buildAutoField(routeDTO, true, UserContext.getUserId());
        int insert = getBaseMapper().insert(routeDTO);

        if (insert != 1) {
            throw new RiceBallBizErrorException("插入子功能失败！");
        }

        MenuRoutePO menuRoutePO = new MenuRoutePO();
        menuRoutePO.setMenuId(routeDTO.getMenuId());
        menuRoutePO.setRouteId(routeDTO.getId());
        menuRoutePO.setWeight(routeDTO.getWeight());
        insert = menuRouteMapper.insert(menuRoutePO);

        return ApiR.msgData(insert == 1, "新增功能成功", "新增功能失败", routeDTO);
    }

    @Override
    public boolean edit(RouteDTO routeDTO) {
        checkRouteBeforeDb(routeDTO);

        RoutePO route = getBaseMapper().selectById(routeDTO.getId());
        BeanUtils.copyWithoutNull(route, routeDTO);
        BeanUtils.buildAutoField(route, false, UserContext.getUserId());

        int update = getBaseMapper().updateById(route);

        if (update == 1) {
            LambdaQueryWrapper<MenuRoutePO> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(MenuRoutePO::getMenuId, routeDTO.getMenuId())
                    .eq(MenuRoutePO::getRouteId, routeDTO.getId());
            MenuRoutePO menuRoutePO = menuRouteMapper.selectOne(wrapper);
            menuRoutePO.setWeight(routeDTO.getWeight());
            update = menuRouteMapper.update(menuRoutePO, wrapper);
        }
        return update == 1;
    }

    /**
     * 数据库操作前的检测
     *
     * @param routeDTO
     */
    private void checkRouteBeforeDb(RouteDTO routeDTO) {
        if (StrUtil.isEmpty(routeDTO.getMenuId())) {
            throw new RiceBallBizWarnException("子功能必须传递菜单id");
        }
        if (StrUtil.isEmpty(routeDTO.getPattern())) {
            throw new RiceBallBizWarnException("子功能必须传递映射路径");
        }
        if (ObjectUtil.isEmpty(routeDTO.getMethodType())) {
            throw new RiceBallBizWarnException("子功能必须传递请求方式");
        }
        if (ObjectUtil.isEmpty(routeDTO.getOnline())) {
            throw new RiceBallBizWarnException("子功能必须传递在线类型");
        }
        if (ObjectUtil.isEmpty(routeDTO.getStatus())) {
            throw new RiceBallBizWarnException("子功能必须传递开启类型");
        }
        if (ObjectUtil.isEmpty(routeDTO.getCheckType())) {
            throw new RiceBallBizWarnException("子功能必须传递校验类型");
        }
        List<RoutePO> routeList;
        if (StrUtil.isEmpty(routeDTO.getId())) {
            //新增功能
            LambdaQueryWrapper<RoutePO> wrapper = Wrappers.<RoutePO>lambdaQuery();
            wrapper.eq(RoutePO::getCode, routeDTO.getCode());
            routeList = getBaseMapper().selectList(wrapper);
            if (routeList.size() > 0) {
                throw new RiceBallBizWarnException("角色编码重复：{}", routeDTO.getCode());
            }
        } else {
            //修改功能
            LambdaQueryWrapper<RoutePO> wrapper = Wrappers.<RoutePO>lambdaQuery();
            wrapper.eq(RoutePO::getCode, routeDTO.getCode());
            routeList = getBaseMapper().selectList(wrapper);
            if (routeList.size() > 1) {
                throw new RiceBallBizWarnException("角色编码重复：{}", routeDTO.getCode());
            }
            if (routeList.size() == 1) {
                if (!routeList.get(0).getId().equals(routeDTO.getId())) {
                    throw new RiceBallBizWarnException("角色编码重复：{}", routeDTO.getCode());
                }
            }
        }
    }

    @Override
    public ApiR<Void> delete(List<String> ids) {
        ApiRc<Void> del = ApiRc.buildResultCount(ids.size());
        for (String id : ids) {
            try {
                RoutePO routePO = getBaseMapper().selectById(id);
                if (routePO == null) {
                    del.append(MessageUtils.format("不存在id为{}的数据<br/>", id));
                    continue;
                }

                //1。删除功能菜单关联
                LambdaQueryWrapper<MenuRoutePO> wrapperMenu = Wrappers.lambdaQuery();
                wrapperMenu.eq(MenuRoutePO::getRouteId, id);

                //2.删除角色功能关联
                LambdaQueryWrapper<RoleRightPO> wrapperRole = Wrappers.lambdaQuery();
                wrapperRole.eq(RoleRightPO::getRouteId, id);

                TransactionUtils.doInTransactionWithRequired(() -> {
                    menuRouteMapper.delete(wrapperMenu);
                    roleRightMapper.delete(wrapperRole);
                    //3。删除子功能
                    getBaseMapper().deleteById(id);
                    return Void.class;
                });

                del.success();
            } catch (Exception e) {
                log.error("删除子功能失败，id：{}", id, e);
                del.append(MessageUtils.format("id为{}子功能删除失败:{}<br/>", id, e.getMessage()));
            }
        }
        return ApiRc.getResult(del);
    }

    @Override
    public Page<RoutePO> selectPage(Page<RoutePO> page, RoutePO routePO) {
        LambdaQueryWrapper<RoutePO> wrapper = Wrappers.<RoutePO>lambdaQuery();
        if (StrUtil.isNotEmpty(routePO.getCode())) {
            wrapper.eq(RoutePO::getCode, routePO.getCode());
        }
        if (StrUtil.isNotEmpty(routePO.getName())) {
            wrapper.like(RoutePO::getName, routePO.getName());
        }
        if (ObjectUtil.isNotEmpty(routePO.getMethodType())) {
            wrapper.like(RoutePO::getMethodType, routePO.getMethodType());
        }
        if (StrUtil.isNotEmpty(routePO.getMenuId())) {
            wrapper.like(RoutePO::getMenuId, routePO.getMenuId());
        }
        if (ObjectUtil.isNotEmpty(routePO.getOnline())) {
            wrapper.like(RoutePO::getOnline, routePO.getOnline());
        }
        if (ObjectUtil.isNotEmpty(routePO.getStatus())) {
            wrapper.like(RoutePO::getStatus, routePO.getStatus());
        }
        if (ObjectUtil.isNotEmpty(routePO.getCheckType())) {
            wrapper.like(RoutePO::getCheckType, routePO.getCheckType());
        }
        return getBaseMapper().selectPage(page, wrapper);
    }
}

